package com.kepler.social.common.utils;

import com.kepler.social.common.exception.ServiceException;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionUtil {

    /**
     * 将val转换成typeCla对应的类型
     *
     * @param typeCla
     * @param val
     * @param <T>
     * @return
     */
    public static <T> T convertClass(Class<T> typeCla, String val) {
        String name = typeCla.getName();
        try {
            switch (name) {
                case "int":
                case "java.lang.Integer":
                    return (T) Integer.valueOf(val);
                case "byte":
                case "java.lang.Byte":
                    return (T) Byte.valueOf(val);
                case "boolean":
                case "java.lang.Boolean":
                    return (T) Boolean.valueOf(val);
                case "double":
                case "java.lang.Double":
                    return (T) Double.valueOf(val);
                case "float":
                case "java.lang.Float":
                    return (T) Float.valueOf(val);
                case "long":
                case "java.lang.Long":
                    return (T) Long.valueOf(val);
                case "short":
                case "java.lang.Short":
                    return (T) Short.valueOf(val);
                default:
                    if (!typeCla.isPrimitive()) { // 判断基本类型
                        if (typeCla.equals(String.class)) { // 如果是string则直接返回
                            return (T) val;
                        }
                        try {
                            return "".equals(val) ? null : typeCla.getConstructor(String.class).newInstance(val);
                        } catch (NoSuchMethodException e) {
                            throw new ServiceException(String.format("类[%s]没有参数未String构造", name), e);
                        } catch (InvocationTargetException e) {
                            throw new ServiceException(String.format("数值[%s]无法转换为类型[%s]", val, name), e);
                        } catch (InstantiationException e) {
                            throw new ServiceException(String.format("类[%s]没有newInstance方法", name), e);
                        } catch (IllegalAccessException e) {
                            throw new ServiceException(String.format("无权限访问类[%s]的newInstance方法", name), e);
                        } catch (IllegalArgumentException e) {
                            throw new ServiceException(String.format("数值[%s]无法转换为类型[%s]", name), e);
                        }
                    } else {
                        throw new ServiceException(String.format("类型[%s]未做适配", name));
                    }
            }
        } catch (NumberFormatException e) {
            throw new ServiceException(String.format("数值[%s]和待转换的类型[%s]不匹配", val, name), e);
        }
    }

    /**
     * 确认fieldName在clazz存在之后，创建一个clazz的对应，并将val设置到对应的属性上
     *
     * @param clazz
     * @param filedName
     * @param val
     * @param <T>
     * @return
     */
    public static <T> T checkAndSetFieldValue(Class<T> clazz, String filedName, Object val) {
        Object target;
        try {
            target = clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException e) {
            throw new ServiceException(String.format("类[%s]没有newInstance方法", clazz.getName()), e);
        } catch (IllegalAccessException e) {
            throw new ServiceException(String.format("无权限访问类[%s]没有newInstance方法", clazz.getName()), e);
        } catch (InvocationTargetException e) {
            throw new ServiceException(String.format("无法转换为类型[%s]", clazz.getName()), e);
        } catch (NoSuchMethodException e) {
            throw new ServiceException(String.format("类[%s]没有无参构造", clazz.getName()), e);
        }
        for (Field field : clazz.getDeclaredFields()) {
            if (field.getName().equals(filedName)) {
                try {
                    setFieldValue(target, filedName, val);
                    return (T) target;
                } catch (InvocationTargetException e) {
                    throw new ServiceException(String.format("数值[%s]无法转换为类型[%s]", val, field.getClass().getName()), e);
                } catch (IllegalAccessException e) {
                    throw new ServiceException(String.format("无权限访问类[%s]的[%s]", clazz.getName(), filedName), e);
                } catch (NoSuchFieldException e) {
                    throw new ServiceException(String.format("类[%s]没有对应的属性[%s]", clazz.getName(), filedName), e);
                }
            }
        }
        return null;
    }

    /**
     * 将val设置到target对应的filedName属性上
     *
     * @param target
     * @param filedName
     * @param val
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    public static void setFieldValue(Object target, String filedName, Object val)
            throws InvocationTargetException, IllegalAccessException, NoSuchFieldException {
        Field field = target.getClass().getDeclaredField(filedName);
        setAccessibleValue(target, field, val);
    }

    /**
     * 将val通过accessibleObject设置到target上
     *
     * @param target
     * @param accessibleObject 可以是方法也可以是属性
     * @param val
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void setAccessibleValue(Object target, AccessibleObject accessibleObject, Object val)
            throws InvocationTargetException, IllegalAccessException {
        accessibleObject.setAccessible(true);
        if (accessibleObject instanceof Method) {
            ((Method) accessibleObject).invoke(target, val);
        }
        if (accessibleObject instanceof Field) {
            ((Field) accessibleObject).set(target, val);
        }
    }

}